import { Suspense, FC, forwardRef, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react';
import { Canvas, useFrame, useLoader, useThree, ThreeEvent } from '@react-three/fiber';
import { Sparkles, Shadow, Environment, Grid, Helper, OrbitControls, PerspectiveCamera, useGLTF, useHelper, Stage, Float } from '@react-three/drei';
import { BufferGeometry, Color, DirectionalLight, DirectionalLightHelper, DoubleSide, Mesh, MeshLambertMaterial, MeshPhongMaterial, PCFShadowMap, PCFSoftShadowMap, ShaderMaterial, SphereGeometry, TextureLoader, Vector2, Vector3 } from 'three';
import { EffectComposer, SMAA, Selection, Outline, Select } from '@react-three/postprocessing'

const ShaderTestWithSMAA: FC = () => {
  const oThree = useThree();
  oThree.camera.position.y = 0;
  // oThree.gl.
  console.log('oThree', oThree);

  const uTime = { value: 0 };

  useFrame((state, delta) => {
    uTime.value += delta;
  })
  const params = {
    vertexShader: /* GLSL */ `
      varying vec3 vColor;
      varying vec2 vUv;
      attribute vec3 color;
      void main() {
        vColor = color;
        vUv = uv;
        gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
      }
    `,
    fragmentShader: /* GLSL */ `
      varying vec3 vColor;
      uniform float uTime;
      varying vec2 vUv;
      void main() {
        // gl_FragColor = vec4(vColor, 1.0);
        // float n = abs(sin(uTime));
        float verticalBand = step(0.5, fract(vUv.x * 3.0));
        float horizontalBand = step(0.5, fract(vUv.y * 3.0));
        // float color = mix(verticalBand, horizontalBand, 1.0);
        float color = abs(verticalBand - horizontalBand);

        gl_FragColor = vec4(vec3(color), 1.0);
      }
    `,
    uniforms: {
      uTime
    }
  }


  return <>
    <Suspense fallback={null}>
      <EffectComposer multisampling={0}>
        <SMAA />
      </EffectComposer>
    </Suspense>

    <mesh>
      <shaderMaterial 
        {...params} 
      />
      <planeGeometry args={[3, 3]}>
        <bufferAttribute 
          array={new Float32Array([
            1.0, 0.0, 0.0,
            1.0, 1.0, 0.0,
            0.0, 0.0, 1.0,
            0.0, 1.0, 0.0,
          ])}
          itemSize={3}
          attach={'attributes-color'}
        />
      </planeGeometry>
    </mesh>


  </>
}


const DemoSelectOutline: FC = () => {
  const Spheres = ({position = new Vector3(1, 1, 1), name}: {position?: Vector3, name: string}) => {
  
    const cb = (e: ThreeEvent<MouseEvent>) => {
      const target = maps.find(d => d.name === e.eventObject.name);
      target!.visible = !target?.visible;
      setMaps([...maps])
    }
    return <>
      <mesh position={position} onClick={cb} name={name}>
        <sphereGeometry args={[.5, 32, 32]} />
        <meshStandardMaterial />

        {/* <Sparkles count={15} scale={2} size={6} speed={0.4} /> */}
        <Shadow rotation={[-Math.PI, 0, 0]} scale={2} position={[0, -1, 0]} color="black" opacity={0.3} />
      </mesh>
    </>
  }

  const [maps, setMaps] = useState([
    {visible: true, position: new Vector3(1, 1, 1), name: 'x1'},
    {visible: false, position: new Vector3(2, 2, 2), name: 'x2'},
    {visible: true, position: new Vector3(3, 3, 3), name: 'x3'},
  ])

  return <>
    <Suspense fallback={null}>
      <Selection>
        <EffectComposer autoClear={false}>
          <Outline blur edgeStrength={100} visibleEdgeColor={0x3399ee} />
        </EffectComposer>
        <Select enabled>
          <Float position={[0.2, 0.1, 0.5]} rotation={[Math.PI / 3.5, 0, 0]} rotationIntensity={2} floatIntensity={2} speed={1.5}>
            {maps.filter(d => d.visible).map((d, i) => <Spheres position={d.position} key={i} name={d.name} />)}
          </Float>
        </Select>
        <Select >
          {maps.filter(d => !d.visible).map((d, i) => <Spheres position={d.position} key={i} name={d.name} />)}
        
        </Select>
      </Selection>
    </Suspense>
  </>
}

const Init: FC = () => {  
  return (
    <div className='full center'>
      <Canvas>
        <Environment preset='forest' background backgroundBlurriness={0.5} />
        <Light />
        <group position-y={0.01}>
          {/* <Grid args={[10, 10]} /> */}
          <axesHelper args={[5]} />
        </group>

        <OrbitControls makeDefault />


        {/* <ShaderTestWithSMAA /> */}
        <DemoSelectOutline />
      </Canvas>
    </div>
  );
};

export default Init;

function Light() {
  const oThree = useThree();
  oThree.scene.background = new Color(0xdddddd);

  const directionalLightRef = useRef<DirectionalLight>(null!);
  useHelper(directionalLightRef, DirectionalLightHelper);

  useEffect(() => {
    console.log(directionalLightRef.current);
    // directionalLightRef.current.shadow.bias = 1
    directionalLightRef.current.shadow.bias = 0.0001;
  }, []);

  return <>
    <ambientLight intensity={1} />
    <directionalLight
      ref={directionalLightRef}
      position={[2, 3, 2]}
      intensity={3}
      castShadow
      shadow-mapSize-width={1024}
      shadow-mapSize-height={1024}
    />
    {/* <directionalLight position={[-2, -2, 5]} intensity={1} /> */}
    {/* <Helper type={DirectionalLightHelper} args={[directionalLightRef, 2]} /> */}
    {/* <directionalLightHelper light={directionalLightRef} /> */}
  </>
}